#include "DeviceManager.h"
#include <qmetatype.h>

//constructor
DeviceManager::DeviceManager(MainWindow &mw, Desk &d, QObject *parent): QObject(), m_mainWindow(&mw), m_desk(&d) {
	//create the disconnect timer and set up its connection
	m_checkDisconnectTimer = new QTimer(this);
	QObject::connect(m_checkDisconnectTimer, SIGNAL(timeout()), this, SLOT(checkForDisconnect()));
	
	//(To use KeyboardHandler, uncomment the following 3 lines.)
	//m_handler = new KeyboardHandler();
	//m_keyboardlistener = new KeyboardListener(&mw);
	//connect(m_keyboardlistener, SIGNAL(signalKeyStroke(int)), m_handler, SLOT(slotKeyStroke(int)));

	//initialize the rest of the objects
	this->init();

}

//deconstructor
DeviceManager::~DeviceManager() {
	delete m_checkDisconnectTimer;

	//The following only when using KeyboardHandler
	//delete m_handler;
	//delete m_keyboardlistener;
}

//instantiates handler and listener and sets up connections
void DeviceManager::init() {
	//instantiation (comment out when using KeyboardHandler)
	m_handler = new KinectHandler(this);
	m_listener = new KinectListener((KinectHandler *)m_handler);

	//connect the listener's startup signal to the handler and start the listener's thread
	//(comment out when using KeyboardHandler)
	connect(m_listener, SIGNAL(signalKinectConnected()), m_handler, SLOT(receiveKinectConnected()));
	m_listener->start(); 
	
	//register these as meta types so that a QueuedConnection can be used since we are communicating across threads
	qRegisterMetaType<InputPoint>("InputPoint");
	qRegisterMetaType<Qt::Axis>("Qt::Axis");

	//connect signals from the handler to the mainwindow
	connect(m_handler, SIGNAL(signalAddedInput(InputPoint)), m_mainWindow, SLOT(slotAddInput(InputPoint)),Qt::QueuedConnection);
	connect(m_handler, SIGNAL(signalUpdateCursor(InputPoint)), m_mainWindow, SLOT(slotUpdateCursor(InputPoint)),Qt::QueuedConnection);
	connect(m_handler, SIGNAL(signalSelect(InputPoint)), m_mainWindow, SLOT(slotSelect(InputPoint)), Qt::QueuedConnection);
	connect(m_handler, SIGNAL(signalRemovedInput(int, bool)), m_mainWindow, SLOT(slotRemoveInput(int, bool)), Qt::QueuedConnection);
	connect(m_handler, SIGNAL(signalDeselect(InputPoint)), m_mainWindow, SLOT(slotDeselect(InputPoint)));
	connect(m_handler, SIGNAL(signalBrowseImportMenu(int)), m_mainWindow, SLOT(slotBrowseImportMenu(int)));
	connect(m_handler, SIGNAL(signalBrowseLoadMenu(int)), m_mainWindow, SLOT(slotBrowseLoadMenu(int)));
	connect(m_handler, SIGNAL(signalSetCursorRed(int)), m_mainWindow, SLOT(setCursorRed(int)));
	connect(m_handler, SIGNAL(signalSetCursorGreen(int)), m_mainWindow, SLOT(setCursorGreen(int)));
	connect(m_handler, SIGNAL(signalRevertCursor1()), m_mainWindow, SLOT(slotRevertCursor1()));
	connect(m_handler, SIGNAL(signalRevertCursor2()), m_mainWindow, SLOT(slotRevertCursor2()));
	connect(m_handler, SIGNAL(signalDeviceConnected()), m_mainWindow, SLOT(slotDeviceConnected()));

	//connect signals from the handler to the desk
	connect(m_handler, SIGNAL(signalMove(double, double)), m_desk, SLOT(slotMove(double, double)));
	connect(m_handler, SIGNAL(signalScale(double)), m_desk, SLOT(slotScale(double)));
	connect(m_handler, SIGNAL(signalRotate(double, Qt::Axis)), m_desk, SLOT(slotRotate(double, Qt::Axis)));
	connect(m_handler, SIGNAL(signalSaveState()), m_desk, SLOT(slotSaveState()));
	connect(m_handler, SIGNAL(signalUnsave()), m_desk, SLOT(slotUnsave()));
	connect(m_handler, SIGNAL(signalFlip(int)), m_desk, SLOT(slotFlip(int)));
	connect(m_handler, SIGNAL(signalPrepareTransform(qreal, qreal, qreal, qreal, qreal, qreal)), m_desk, SLOT(slotPrepareTransform(qreal, qreal, qreal, qreal, qreal, qreal)));
	connect(m_handler, SIGNAL(signalTransform(qreal, qreal, qreal, qreal, qreal, qreal)), m_desk, SLOT(slotTransform(qreal, qreal, qreal, qreal, qreal, qreal)));

	//connect the state changed callback from the desk to the handler
	connect(m_desk, SIGNAL(signalInputStateChange(int, InputState)), m_handler, SLOT(slotUpdateInputPoint(int, InputState)));

	//set the timer to check for a disconnected device every 3 seconds
	m_checkDisconnectTimer->setInterval(3000);
}

//a slot to start timer since it needs to be started from a different thread
void DeviceManager::startTimer() {
	m_checkDisconnectTimer->start();
}

//checks if listener can still communicate with device and attempts to reconnect if need be
//(comment out body if using KeyboardHandler)
void DeviceManager::checkForDisconnect() {
	if(!m_listener->checkDeviceConnection()) {
		m_mainWindow->slotDeviceConnected();
		m_checkDisconnectTimer->stop();
		m_listener->exit();
		m_mainWindow->makeNewDeviceManager();
	}
}
